<?php if(!defined('SPRITCH')) { exit(); }

// Spritch - An opensource PHP5 web framework

// Author: Luca Degasperi
// Licence: GNU GPL
// Site: http://www.spritch.org/

// Class: Spritch
// Summary: This class provides the basic core functionalities
// Since: 0.9.1

class spritch
{
	protected static $instance = null;
	protected static $started = false;
	
	private static function instance()
	{
		if(is_null(self::$instance))
			self::$instance = new spritch();
		return self::$instance;
	}
	
	public static function singleton_array($type = null)
	{
		$instance = self::instance();
		if(!is_null($type) and array_key_exists($type,$instance->singleton))
			return $instance->singleton[$type];
		else if(!is_null($type))
			return array();
		return $instance->singleton;
	}
	
	public static function singleton($class,$args = array(),$new = false)
	{
		$class = strtolower($class);
		if(strpos($class,'.') === false)
			$class .= '.system';
		$tmp = explode('.',$class);
		list($file,$type) = $tmp;
		$folder = '';
		if(strpos($file,'/') !== false)
		{
			$tmp = explode('/',$file);
			$tmpcount = count($tmp)-1;
			for($i = 0; $i < $tmpcount; $i++)
				$folder .= $tmp[$i].DS;
			$file = $tmp[count($tmp)-1];
		}
		$instance = self::instance();
		if(!$new)
		{
			if(!array_key_exists($type,$instance->singleton))
				$instance->singleton[$type] = array();
			if(array_key_exists($folder.$file,$instance->singleton[$type]))
				return $instance->singleton[$type][$folder.$file];
		}		
		$class = $file;
		if($type != 'system' and $type != 'view' and $type != 'database')
			$class = $file.'_'.$type;
		$search = '';
		switch($type)
		{
			case 'library': $search = 'libraries'; break;
			case 'controller': $search = 'controllers'; break;
			case 'helper': $search = 'helpers'; break;
			case 'model': $search = 'models'; break;
			case 'hook': $search = 'hooks'; break;
			case 'system': $search = 'system'; break;
		}
		$object = null;
		if($type == 'view')
			$object = new view($args);
		else if($type == 'database')
			$object = new database($args);
		else
		{
			$path = $instance->exists($folder.$file,$search);
			if($path)
			{
				include_once($path);
				$object = new $class($args);
			}
		}
		if($new and !is_null($object))
			return $object;
		else if(!is_null($object))
			return $instance->singleton[$type][$folder.$file] = $object;
		return null;
	}
	
	public static function setup()
	{
		if(self::$started)
			return;
		define('VERSION','1.1.5');
		$instance = self::instance();
		ob_start();
		error_reporting(E_ALL);
		$instance->profiler      = get('profiler');
		$instance->profiler->benchmark('system');
		set_error_handler(array(&$instance,'handler'));
		set_exception_handler(array(&$instance,'handler'));
		spl_autoload_register(array(&$instance,'autoload'));
		set_magic_quotes_runtime(0);
		$instance->profiler->benchmark('basic classes loading');
		$instance->configuration = get('configuration');
		$instance->uri           = get('uri');
		$instance->input         = get('input');
		$instance->output        = get('output');
		$instance->profiler->benchmark('basic classes loading');
		if(!$instance->output->read_cache())
		{
			$instance->router        = get('router');
			$instance->event         = get('event');
			$instance->storage       = get('storage');
			$instance->language      = get('language');
			if(file_exists(CONFIGURATION.DS.'autoload'.EXT))
			{
				include_once(CONFIGURATION.DS.'autoload'.EXT);
				foreach($autoload as $key => $value)
					$instance->$key = get($value);
			}
			$instance->profiler->benchmark('controller execution');
			$instance->event->call('pre-controller');
			$instance->router->route();
			$instance->event->call('post-controller');
			$instance->profiler->benchmark('controller execution');
			$instance->output->render();
		}
		if($instance->configuration->get('profiler',false))
			$instance->profiler->render();
		self::$started = true;
	}
	
	private $singleton = array();
	private $vars = array();
	
	public function __construct() { }
	
	public function __get($key)
	{
		$instance = self::instance();
		if(array_key_exists($key,$instance->vars))
			return $instance->vars[$key];
		return null;
	}
	
	public function __set($key,$object)
	{
		$instance = self::instance();
		if(!array_key_exists($key,$instance->vars))
			$instance->vars[$key] = $object;
	}
	
	public function __call($method,$args = array())
	{
		$this->profiler->error('call to undefined method '.$method);
	}
	
	public function handler($id,$message = null,$file = null,$line = null)
	{
		$this->profiler->error($message,array('file' => $file,'line' => $line));
	}
	
	public function autoload($class)
	{
		if(strpos($class,'.') !== false)
			return;
		if(file_exists(SYSTEM.DS.$class.EXT))
			require(SYSTEM.DS.$class.EXT);
		return;
	}
	
	public function plugins()
	{
		$plugins = array('framework'.DS);
		if(defined('PLUGINS'))
		{
			array_push($plugins,MODULE.DS);
			$handle = opendir(PLUGINS);
			while($file = readdir($handle))
				if(!is_file($file) and $file != '.' and $file != '..')
					array_push($plugins,PLUGINS.DS.$file.DS);
			closedir($handle);
		}
		return $plugins;
	}
	
	public function exists($what,$where,$ext = null)
	{
		if(is_null($ext))
			$ext = EXT;
		$instance = self::instance();
		$plugins = $instance->plugins();
		$i = -1;
		do
		{
			$i++;
			if(file_exists($plugins[$i].$where.DS.$what.$ext))
				return $plugins[$i].$where.DS.$what.$ext;
		}
		while(!file_exists($plugins[$i].$where.DS.$what.$ext) and $i < count($plugins)-1);
		return false;
	}
}

function get($class,$args = array())
{
	return spritch::singleton($class,$args);
}

function get_new($class,$args = array())
{
	return spritch::singleton($class,$args,true);
}

class model extends spritch
{
	public function __construct() { }
}

class view extends spritch
{
	private $data = array();
	private $priority = false;
	
	public function  __construct($data = array())
	{
		$this->data = array();
	}
	
	public function __get($key)
	{
		if(array_key_exists($key,$this->data))
			return $this->data[$key];
		return '';
	}
	
	public function __set($key,$value)
	{
		$this->data[$key] = $value;
	}
	
	public function get_data()
	{
		if(!empty($this->data))
			return $this->data;
		return array();
	}
	
	public function use_priority()
	{
		$output = get('output');
		$output->use_priority();
		$this->priority = true;
	}
	
	public function has_priority()
	{
		return $this->priority;
	}
}

class controller extends spritch
{
	public function __construct() { }
	
	public function __call($method,$args = array()) { }
}

class library extends spritch
{
	public function __construct() { }
}

class helper extends spritch
{
	public function __construct() { }
}

class hook extends spritch
{
	public function __construct() { }
}
?>